package model

import (
	. "api/util"
	"database/sql"
	"encoding/json"
	"time"
	jwt "github.com/dgrijalva/jwt-go"
)

type (
	Customer struct {
		Id           	int    	`json:"id"`
		Phone        	string 	`json:"phone"`
		CreatedDate  	int    	`json:"created_date"`
		UpdatedDate  	int    	`json:"updated_date"`
		IsPromotion  	int    	`json:"is_promotion"`
		PromotionId  	int    	`json:"promotion_id"`
		SourceUserId 	int    	`json:"source_user_id"`
	}
	CustomerInfo struct {
		Id           int	`json:"id"`
		Phone        string	`json:"phone"`
	}
	CustomerRecord struct {
		Id           	int    	`json:"id"`
		ProductType  	int  	`json:"product_type"`
		ProductId    	int 	`json:"product_id"`
		SourceCustomer 	int 	`json:"source_customer"`
		Link            string	`json:"link"`
		CustomerId      int     `json:"customer_id"`
		CreatedDate  	int    	`json:"created_date"`
		UpdatedDate  	int    	`json:"updated_date"`
	}
)

func redisCustomer() (ret []*Customer, err error) {
	err = rdb.Del(ctx, "customer").Err()
	if err != nil {
		return ret, err
	}

	rows, err := db.Query("SELECT * FROM customer ORDER BY id")
	if err != nil {
		return ret, err
	}

	defer rows.Close()

	for rows.Next() {
		cm := Customer{}
		if err := rows.Scan(&cm.Id, &cm.Phone, &cm.CreatedDate, &cm.UpdatedDate, &cm.IsPromotion, &cm.PromotionId, &cm.SourceUserId); err != nil {
			return ret, err
		}

		ret = append(ret, &cm)

		jsonStu, err := json.Marshal(cm)
		if err != nil {
			return ret, err
		}

		err = rdb.RPush(ctx, "customer", jsonStu).Err()
		if err != nil {
			return ret, err
		}
	}

	return ret, nil
}

func redisCustomerRecord() (ret []*CustomerRecord, err error) {
	err = rdb.Del(ctx, "customer_record").Err()
	if err != nil {
		return ret, err
	}

	rows, err := db.Query("SELECT * FROM customer_record ORDER BY id")
	if err != nil {
		return ret, err
	}

	defer rows.Close()

	for rows.Next() {
		cr := CustomerRecord{}
		err := rows.Scan(&cr.Id, &cr.ProductType, &cr.ProductId, &cr.SourceCustomer, &cr.Link, &cr.CustomerId, &cr.CreatedDate, &cr.UpdatedDate)
		if err != nil {
			return ret, err
		}

		ret = append(ret, &cr)
		jsonStu, err := json.Marshal(cr)
		if err != nil {
			return ret, err
		}

		err = rdb.RPush(ctx, "customer_record", jsonStu).Err()
		if err != nil {
			return ret, err
		}
	}

	return ret, nil
}

func (u *Customer) GetCustomer() (ret []*Customer, err error) {
	vals, err := rdb.LRange(ctx, "customer", 0, -1).Result()
	if err != nil {
		return nil, err
	}

	if len(vals) > 0 {
		for _, v := range vals {
			cm := Customer{}
			err := json.Unmarshal([]byte(v), &cm)
			if err != nil {
				return ret, err
			}

			ret = append(ret, &cm)
		}

		return ret, nil
	}

	ret, err = redisCustomer()
	if err != nil {
		return ret, err
	}

	return ret, nil
}

func (cm *Customer) CreateCustomer(phone string, sourceUserId int) (token string, err error) {
	tx, err := db.Begin()

	stmt, err := db.Prepare("SELECT * FROM customer WHERE phone=?")
	if err != nil {
		tx.Rollback()
		return token, err
	}

	err = stmt.QueryRow(phone).Scan(&cm.Id, &cm.Phone, &cm.CreatedDate, &cm.UpdatedDate, &cm.IsPromotion, &cm.PromotionId, &cm.SourceUserId)
	if err != nil && err != sql.ErrNoRows {
		tx.Rollback()
		return token, err
	}

	cid := uint(cm.Id)
	if err == sql.ErrNoRows {
		stmt1, err := tx.Prepare("INSERT customer SET phone=?, created_date=?, updated_date=?, is_promotion=?, promotion_id=?, source_user_id=?")
		if err != nil {
			tx.Rollback()
			return token, err
		}

		_, err = stmt1.Exec(phone, time.Now().Unix(), time.Now().Unix(), 0, 0, sourceUserId)
		if err != nil {
			tx.Rollback()
			return token, err
		}

		stmt3, err := tx.Prepare("SELECT id FROM customer WHERE phone=?")
		if err != nil {
			tx.Rollback()
			return token, err
		}

		err = stmt3.QueryRow(phone).Scan(&cid)
		if err != nil {
			tx.Rollback()
			return token, err
		}
	}

	tx.Commit()

	_, err = redisCustomer()
	if err != nil {
		tx.Rollback()
		return token, err
	}

	tokenCliams := Claims{
		Id: cid,
		StandardClaims: jwt.StandardClaims{
			ExpiresAt: time.Now().Unix() + 24 * 3600000,
		},
	}

	token, err = MakeCliamsToken(tokenCliams)

	return token, nil
}

func (u *CustomerRecord) GetCustomerRecord() (ret []*CustomerRecord, err error) {
	vals, err := rdb.LRange(ctx, "customer_record", 0, -1).Result()
	if err != nil {
		return nil, err
	}

	if len(vals) > 0 {
		for _, v := range vals {
			cr := CustomerRecord{}
			err := json.Unmarshal([]byte(v), &cr)
			if err != nil {
				return ret, err
			}

			ret = append(ret, &cr)
		}

		return ret, nil
	}

	ret, err = redisCustomerRecord()
	if err != nil {
		return ret, err
	}

	return ret, nil
}

func (cr *CustomerRecord) CreateCustomerRecord() error {
	tx, err := db.Begin()
	if err != nil {
		return err
	}

	stmt, err := tx.Prepare("SELECT id FROM customer_record WHERE customer_id=? AND link=?")
	if err != nil {
		tx.Rollback()
		return err
	}

	var id int
	err = stmt.QueryRow(cr.CustomerId, cr.Link).Scan(&id)
	if err != nil && err != sql.ErrNoRows {
		tx.Rollback()
		return err
	}

	if err == sql.ErrNoRows {
		stmt1, err := tx.Prepare("INSERT customer_record SET product_type=?, product_id=?, source_customer=?, link=?, customer_id=?, created_date=?, updated_date=?")
		if err != nil {
			tx.Rollback()
			return err
		}

		_, err = stmt1.Exec(cr.ProductType, cr.ProductId, cr.SourceCustomer, cr.Link, cr.CustomerId, time.Now().Unix(), time.Now().Unix())
		if err != nil {
			tx.Rollback()
			return err
		}
	} else {
		stmt2, err := tx.Prepare("UPDATE customer_record SET product_type=?, product_id=?, source_customer=?, link=?, customer_id=?, updated_date=? WHERE id=?")
		if err != nil {
			tx.Rollback()
			return err
		}

		_, err = stmt2.Exec(cr.ProductType, cr.ProductId, cr.SourceCustomer, cr.Link, cr.CustomerId, time.Now().Unix(), id)
		if err != nil {
			tx.Rollback()
			return err
		}
	}

	tx.Commit()

	_, err = redisCustomerRecord()
	if err != nil {
		tx.Rollback()
		return err
	}

	return nil
}